use std::{os::raw::c_void};

use nix::{
    errno::Errno,
    libc::{mprotect,sysconf, PROT_EXEC, PROT_READ, PROT_WRITE, _SC_PAGESIZE},
};

static mut BACK: [u8; 5] = [0; 5];

fn main() {
    let hook_p = hook as isize;
    let hello_p = hello as isize;
    let page_size = unsafe { sysconf(_SC_PAGESIZE) } as usize;
    let aligned_addr = hello_p as usize & !(page_size - 1);
    let len = (5 + page_size - 1) & !(page_size - 1);
    let mut hook_code: [u8; 5] = [0xe9, 0, 0, 0, 0];
    unsafe {
        std::ptr::copy_nonoverlapping(hello_p as *const u8, (&raw mut BACK).cast::< u8>(), 5);
        let err = mprotect(
            aligned_addr as *mut c_void,
            len,
            PROT_READ | PROT_WRITE | PROT_EXEC,
        );
        println!(" {err} {}", Errno::last().desc());
        // 写入跳转指令
        let offset = (hook_p - hello_p - 5) as i32;
        std::ptr::write_unaligned(hook_code.as_mut_ptr().add(1) as *mut i32, offset);
        std::ptr::copy_nonoverlapping(hook_code.as_ptr(), hello_p as *mut u8, 5);
        hello();
        hello();
        hello();
    }
    println!("{:x?}", hook_code);
}

fn hook() {
    println!("hook");
}

fn hello() {
    println!("helloworld");
}
